using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Collections.ObjectModel;
using System.Drawing.Drawing2D;
using Mbs.SmartParts;
using Mbs.Services;

namespace Mbs.Windows
{
	public partial class OutlookBarWorkspace : UserControl, IWorkspace
	{
        private static readonly OutlookBarSmartPartInfo nullSmartPartInfo = new OutlookBarSmartPartInfo("Item",null);

        Dictionary<object, ToolStripButton> _smartParts;
        Dictionary<ToolStripButton, ToolStripButton> _buttons;
        Dictionary<string, string> _topics = new Dictionary<string, string>();
        int _visibleCount = -1;
        int _lastCount = -1;
        int _maxHeight;
        
        public OutlookBarWorkspace()
		{            
            _smartParts = new Dictionary<object, ToolStripButton>();
            _buttons = new Dictionary<ToolStripButton, ToolStripButton>();
			InitializeComponent();            
            this.stackStrip.ItemHeightChanged += new EventHandler(OnStackStripItemHeightChanged);
            // Set Height
            UpdateSplitter();           
		}             

		private void _deckWorkspace_SmartPartClosing(object sender, WorkspaceCancelEventArgs e)
		{
			if (_smartParts.ContainsKey(e.SmartPart))
			{
				this.stackStrip.Items.Remove(_smartParts[e.SmartPart]);
                this.overflowStrip.Items.Remove(_buttons[_smartParts[e.SmartPart]]);
                UpdateSplitter();
			}
        }

        #region IWorkspace memebers
        public void Activate(object smartPart)
		{
			_deckWorkspace.Activate(smartPart);
            OnSmartPartActivated(smartPart);           
		}

		public object ActiveSmartPart
		{
			get { return _deckWorkspace.ActiveSmartPart; }
		}

		public void ApplySmartPartInfo(object smartPart, ISmartPartInfo smartPartInfo)
		{
			_deckWorkspace.ApplySmartPartInfo(smartPart, smartPartInfo);
		}

		public void Close(object smartPart)
		{
			if (_smartParts.ContainsKey(smartPart))
			{
                this.stackStrip.Items.Remove(_smartParts[smartPart]);
                this.overflowStrip.Items.Remove(_buttons[_smartParts[smartPart]]);
                UpdateSplitter();
			}
			_deckWorkspace.Close(smartPart);
			OnSmartPartActivated(_deckWorkspace.ActiveSmartPart);
		}

		public void Hide(object smartPart)
		{
			_deckWorkspace.Hide(smartPart);

		}
		public void Show(object smartPart)
		{
			ISmartPartInfoProvider provider = smartPart as ISmartPartInfoProvider;
			if (provider != null)
			{
				ISmartPartInfo info = provider.GetSmartPartInfo(typeof(OutlookBarSmartPartInfo));
				if (info != null)
				{
					Show(smartPart, info);
				}
			}
			else
			{
				_deckWorkspace.Show(smartPart);
                OnSmartPartActivated(smartPart);
			}			
		}

		public void Show(object smartPart, ISmartPartInfo smartPartInfo)
		{
			Control ctrl = smartPart as Control;
			if (ctrl != null && _deckWorkspace.SmartParts.Contains(ctrl) == false)
			{
                OutlookBarSmartPartInfo info = smartPartInfo as OutlookBarSmartPartInfo;
				if (info == null)
				{
					info = nullSmartPartInfo;
				}

                // Add new button
                ToolStripButton stackStripButton;
                ToolStripButton overflowStripButton;

                AddNewButton(info, smartPart, out stackStripButton, out overflowStripButton);

                if (info.EventTopicName != null && info.EventTopicName != String.Empty)
                {
                    _topics.Add(stackStripButton.Text, info.EventTopicName);                    
                }
                _smartParts.Add(smartPart, stackStripButton);
                _buttons.Add(stackStripButton, overflowStripButton);

			}
			_deckWorkspace.Show(smartPart, smartPartInfo);
			OnSmartPartActivated(smartPart);
        }

        public event EventHandler<WorkspaceEventArgs> SmartPartActivated
        {
            add
            {
                _deckWorkspace.SmartPartActivated += value;
            }
            remove
            {
                _deckWorkspace.SmartPartActivated -= value;
            }
        }

        public event EventHandler<WorkspaceCancelEventArgs> SmartPartClosing
        {
            add
            {
                _deckWorkspace.SmartPartClosing += value;
            }
            remove
            {
                _deckWorkspace.SmartPartClosing -= value;
            }
        }

        public ReadOnlyCollection<object> SmartParts
        {
            get
            {
                List<object> result = new List<object>();
                foreach (Control ctrl in _deckWorkspace.SmartParts) result.Add(ctrl);
                return result.AsReadOnly();
            }
        }

        #endregion

        #region Support events and methods
        protected virtual void OnClick(object sender, EventArgs e)
        {
            ToolStripButton button = (ToolStripButton)sender;
            _headerLabel.Text = button.Text.Trim();

            _deckWorkspace.Activate(button.Tag);
            OnSmartPartActivated(button.Tag);

            if (_topics.ContainsKey(button.Text))
            {
                string eventTopic = _topics[button.Text];
                if (eventTopic != null)
                    ServiceLocator.MessageBus.Publish(eventTopic, sender, e);
            }
        }

        private void OnSmartPartActivated(object smartPart)
        {
            if (smartPart != null)
            {
                ToolStripButton relatedButton;
                if (_smartParts.TryGetValue(smartPart, out relatedButton))
                {
                    relatedButton.Checked = true;
                }
                ISmartPartInfoProvider provider = smartPart as ISmartPartInfoProvider;
                if (provider != null)
                {
                    ISmartPartInfo info = provider.GetSmartPartInfo(typeof(OutlookBarSmartPartInfo));
                    _headerLabel.Text = info.Title;
                }
                else
                {
                    if (relatedButton != null)
                        _headerLabel.Text = relatedButton.Text.Trim();
                }
            }
        }

        protected virtual void AddNewButton(OutlookBarSmartPartInfo info, object smartPart, out ToolStripButton stackStripButton, out ToolStripButton overflowStripButton)
        {
            stackStripButton = new ToolStripButton();
            stackStripButton.ImageTransparentColor = info.ImageTransparentColor == Color.Empty ? Color.Black : info.ImageTransparentColor;
            stackStripButton.CheckOnClick = true;
            stackStripButton.Image = info.Icon;
            stackStripButton.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
            stackStripButton.Margin = new System.Windows.Forms.Padding(0);
            stackStripButton.Padding = new System.Windows.Forms.Padding(2);
            stackStripButton.Size = new System.Drawing.Size(311, 32);
            stackStripButton.Text = info.Title;
            stackStripButton.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
            stackStripButton.Tag = smartPart;

            overflowStripButton = new ToolStripButton( info.Icon );
            overflowStripButton.ImageTransparentColor = Color.Black;
            overflowStripButton.Alignment = ToolStripItemAlignment.Right;
            overflowStripButton.DisplayStyle = ToolStripItemDisplayStyle.Image;
            overflowStripButton.Text = info.Title;
            overflowStripButton.Tag = smartPart;

            stackStripButton.Click += new EventHandler(this.OnClick);
            overflowStripButton.Click += new EventHandler(this.OnClick);

            int index = this.GetInsertIndex(info.Index);
            this.overflowStrip.Items.Insert(index + 1, overflowStripButton);
            this.stackStrip.Items.Insert(index, stackStripButton);
            this.UpdateSplitter();
        }

        private int GetInsertIndex(double index)
        {
            if (index == -1.0)
                return this.stackStrip.Items.Count;

            int lastIndex = 0;
            foreach (ToolStripButton button in this.stackStrip.Items)
            {
                OutlookBarSmartPartInfo info = ((ISmartPartInfoProvider)button.Tag).GetSmartPartInfo(typeof(OutlookBarSmartPartInfo)) as OutlookBarSmartPartInfo;
                if (info != null)
                {
                    if (info.Index == -1.0 || info.Index > index)
                        break;
                    lastIndex++;
                }
            }
            return lastIndex;
        }

        #endregion
        
        #region StackStrip splitter
        
        private void UpdateSplitter()
        {
            // Set slider increment
            if (this.stackStrip.ItemHeight > 0)
            {
                this.stackStripSplitter.SplitterIncrement = this.stackStrip.ItemHeight;

                // Find visible count                
                _visibleCount = this.stackStrip.Items.Count;

                // Setup BaseStackStrip
                this.overflowStrip.Height = this.stackStrip.ItemHeight;

                // Set splitter distance
                int min = this.stackStrip.ItemHeight + this.overflowStrip.Height;
                int distance = this.stackStripSplitter.Height - this.stackStripSplitter.SplitterWidth - ((_visibleCount * this.stackStrip.ItemHeight) + this.overflowStrip.Height);

                // Set Max
                _maxHeight = (this.stackStrip.ItemHeight * this.stackStrip.ItemCount) + this.overflowStrip.Height + this.stackStripSplitter.SplitterWidth;

                // In case it's sized too small on startup
                if (distance < 0)
                {
                    distance = min;
                }

                // Set Min/Max
                this.stackStripSplitter.SplitterDistance = distance;
                this.stackStripSplitter.Panel1MinSize = min;
            }
        }   

        private void OnStackStripSplitterPaint(object sender, PaintEventArgs e)
        {
            ProfessionalColorTable pct = new ProfessionalColorTable();
            Rectangle bounds = (sender as SplitContainer).SplitterRectangle;

            int squares;
            int maxSquares = 9;
            int squareSize = 4;
            int boxSize = 2;

            // Make sure we need to do work
            if ((bounds.Width > 0) && (bounds.Height > 0))
            {
                Graphics g = e.Graphics;

                // Setup colors from the provided renderer
                Color begin = pct.OverflowButtonGradientMiddle;
                Color end = pct.OverflowButtonGradientEnd;

                // Make sure we need to do work
                using (Brush b = new LinearGradientBrush(bounds, begin, end, LinearGradientMode.Vertical))
                {
                    g.FillRectangle(b, bounds);
                }

                // Calculate squares
                if ((bounds.Width > squareSize) && (bounds.Height > squareSize))
                {
                    squares = Math.Min((bounds.Width / squareSize), maxSquares);

                    // Calculate start
                    int start = (bounds.Width - (squares * squareSize)) / 2;
                    int Y = bounds.Y + 1;

                    // Get brushes
                    Brush dark = new SolidBrush(pct.GripDark);
                    Brush middle = new SolidBrush(pct.ToolStripBorder);
                    Brush light = new SolidBrush(pct.ToolStripDropDownBackground);

                    // Draw
                    for (int idx = 0; idx < squares; idx++)
                    {
                        // Draw grips
                        g.FillRectangle(dark, start, Y, boxSize, boxSize);
                        g.FillRectangle(light, start + 1, Y + 1, boxSize, boxSize);
                        g.FillRectangle(middle, start + 1, Y + 1, 1, 1);
                        start += squareSize;
                    }

                    dark.Dispose();
                    middle.Dispose();
                    light.Dispose();
                }
            }
        }

        private void OnStackStripSplitterMoved(object sender, SplitterEventArgs e)
        {
            if ((_maxHeight > 0) && ((this.stackStripSplitter.Height - e.SplitY) >= _maxHeight))
            {
                // Limit to max height
                this.stackStripSplitter.SplitterDistance = this.stackStripSplitter.Height - _maxHeight;

                // Set to max
                _visibleCount = this.stackStrip.ItemCount;
                int count = this.overflowStrip.Items.Count;

                // Update overflow items
                for (int idx = 1; idx < count; idx++)
                {
                    this.overflowStrip.Items[idx].Visible = false;
                }
                _lastCount = _visibleCount;

            }
            else if ((_visibleCount >= 0) && (this.stackStrip.ItemCount > 0))
            {
                // Make sure overflow is correct
                _visibleCount = (this.stackStrip.Height / this.stackStrip.ItemHeight);

                // See if this changed
                if (_lastCount != _visibleCount)
                {
                    int count = this.overflowStrip.Items.Count;

                    // Update overflow items
                    for (int idx = 1; idx < count; idx++)
                    {
                        this.overflowStrip.Items[count-idx].Visible = (idx < (count - _visibleCount));
                    }

                    // Update last
                    _lastCount = _visibleCount;
                }
            }
        }

        private void OnStackStripItemHeightChanged(object sender, EventArgs e)
        {
            UpdateSplitter();
        }

        private void showMoreButtonsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_visibleCount < this.stackStrip.Items.Count)
            {
                this.stackStripSplitter.SplitterDistance -= this.stackStrip.ItemHeight;
            }
        }

        private void showFewerButtonsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_visibleCount > 0)
            {
                this.stackStripSplitter.SplitterDistance += this.stackStrip.ItemHeight;
            }
        }
        #endregion      
                
	}
}
